package com.ruowei.modules.webSocket.service;

import com.querydsl.jpa.impl.JPAQueryFactory;
import com.ruowei.config.ApplicationProperties;
import com.ruowei.modules.member.domain.Member;
import com.ruowei.modules.member.repository.MemberRepository;
import com.ruowei.modules.sys.utils.CommonUtils;
import com.ruowei.modules.webSocket.domain.Message;
import com.ruowei.modules.webSocket.domain.MessagePush;
import com.ruowei.modules.webSocket.domain.enumeration.MessageType;
import com.ruowei.modules.webSocket.domain.enumeration.ReceiverType;
import com.ruowei.modules.webSocket.domain.enumeration.SenderType;
import com.ruowei.modules.webSocket.repository.MessagePushRepository;
import com.ruowei.modules.webSocket.repository.MessageRepository;
import com.ruowei.modules.webSocket.web.task.JPushTask;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.io.IOException;
import java.time.Instant;
import java.util.Map;

@Service
@Transactional
@Slf4j
public class MessagePushService {

    private final JPAQueryFactory jpaQueryFactory;
    private final MessageRepository messageRepository;
    private final MessagePushRepository messagePushRepository;
    private final JPushTask jPushTask;
    private final ApplicationProperties applicationProperties;
    private final MemberRepository memberRepository;

    public MessagePushService(JPAQueryFactory jpaQueryFactory, MessageRepository messageRepository,
                              MessagePushRepository messagePushRepository, JPushTask jPushTask,
                              ApplicationProperties applicationProperties, MemberRepository memberRepository) {
        this.jpaQueryFactory = jpaQueryFactory;
        this.messageRepository = messageRepository;
        this.messagePushRepository = messagePushRepository;
        this.jPushTask = jPushTask;
        this.applicationProperties = applicationProperties;
        this.memberRepository = memberRepository;
    }

    /**
     * @param senderType    发送方类型
     * @param senderCode    发送方编号
     * @param receiverCode  接收方编号
     * @param messageType   消息类型
     * @param jumpPage      是否跳转
     * @param title         标题
     * @param content       内容
     * @param customMessage 自定义消息体
     * @param receiverType  接收方类型用来判断向哪个App推送
     * @apiNote
     * @author 董兴
     * @date 2020-11-05
     */
    public void pushMessage(SenderType senderType, String senderCode, String receiverCode, MessageType messageType,
                            Boolean jumpPage, String title, String content, Map<String, String> customMessage, ReceiverType receiverType) {
        Assert.isTrue(senderType != null, "消息发送方类型不能为空");
        Assert.isTrue(StringUtils.isNotEmpty(receiverCode), "接收方人员编号不能为空");
        Assert.isTrue(messageType != null, "消息分类不能为空");
        Assert.isTrue(jumpPage != null, "是否跳转不能为空");
        Assert.isTrue(StringUtils.isNotEmpty(content), "消息内容不能为空");

        Message message = saveMessage(senderType, senderCode, receiverCode, messageType, jumpPage, title, content, customMessage);

        if (receiverType.equals(ReceiverType.CAR_APP) || receiverType.equals(ReceiverType.COURIER_APP) || receiverType.equals(ReceiverType.MERCHANT_APP)) {
            //App推送,先用WebSocket 如果失败了 再用极光推送
            try {
                if (WebSocketService.sendMessage(message, receiverCode)) {
                    saveMessagePush(message.getMessageCode(), receiverType, true);
                } else {
                    jPush(receiverType, message);
                }
            } catch (IOException e) {
                jPush(receiverType, message);
                e.printStackTrace();
            }
        }

        if (receiverType.equals(ReceiverType.APPLET)) {
            if (memberRepository.findByOpenId(receiverCode).isPresent()) {
                receiverCode = memberRepository.findByOpenId(receiverCode).get().getAppletToken();
            }
            //小程序推送
            try {
                if (WebSocketService.sendMessage(message, receiverCode)) {
                    saveMessagePush(message.getMessageCode(), receiverType, true);
                } else {
                    saveMessagePush(message.getMessageCode(), receiverType, false);
                }
            } catch (IOException e) {
                saveMessagePush(message.getMessageCode(), receiverType, false);
                e.printStackTrace();
            }
        }
    }

    private void jPush(ReceiverType receiverType, Message message) {
        //极光推送
        MessagePush messagePush = new MessagePush();
        messagePush.setPushCode(CommonUtils.getUUID());
        messagePush.setMessageCode(message.getMessageCode());
        messagePush.setReceiverType(receiverType);
        messagePush.setPushTime(Instant.now());
        messagePush.setRead(false);
        jPushTask.startPushTask(message, messagePush);
    }

    private void saveMessagePush(String messageCode, ReceiverType receiverType, Boolean pushed) {
        MessagePush push = new MessagePush();
        push.setPushCode(CommonUtils.getUUID());
        push.setMessageCode(messageCode);
        push.setReceiverType(receiverType);
        push.setPushTime(Instant.now());
        push.setPushed(pushed);
        push.setRead(false);
        messagePushRepository.save(push);
    }

    private Message saveMessage(SenderType senderType, String senderCode, String receiverCode, MessageType messageType, Boolean jumpPage,
                                String title, String content, Map<String, String> customMessage) {
        Message message = new Message();
        message.setMessageCode(CommonUtils.getUUID());
        message.setSenderType(senderType);
        message.setSenderCode(senderCode);
        message.setReceiverCode(receiverCode);
        message.setMessageType(messageType);
        message.setJumpPage(jumpPage);
        message.setTitle(title);
        message.setContent(content);
        message.setCustomMessage(customMessage);
        message.setCreateTime(Instant.now());
        message.setPlanSendTime(Instant.now());
        message.setRead(false);
        return messageRepository.saveAndFlush(message);
    }
}
